package com.dmp.common.mybatis;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ReuseExecutor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
import org.apache.ibatis.scripting.xmltags.TextSqlNode;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.jdbc.JdbcTransaction;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DataBaseExtendMethod implements ExtendMethod {
	private DataSource dataSource;
	private List<String> extendExpressions = new ArrayList<String>();
	// mibatis配置
	private Configuration config;
	private Executor executor;
	private Map<String, MappedStatement> mStatementMap = new HashMap<String, MappedStatement>();
	private boolean isInited = false;
	private Map<String, String> cacheMap = new HashMap<String, String>();

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public List<String> getExtendExpressions() {
		return extendExpressions;
	}

	public void setExtendExpressions(List<String> extendExpressions) {
		this.extendExpressions = extendExpressions;
	}

	@Override
	public void execute(Map<String, Object> context) {
		if (!isInited) {
			synchronized (this) {
				init();
			}
		}

		for (String exp : extendExpressions) {
			String contextMapKey = StringUtils.substring(exp, StringUtils.indexOf(exp, "{")+1, StringUtils.indexOf(exp, "}")); 
			String contextMapKeyOut = StringUtils.substring(exp, StringUtils.indexOfIgnoreCase(exp, "AS ")+3, StringUtils.indexOfIgnoreCase(exp, " FROM")); 
			Object contextMapObject = context.get(contextMapKey);
			if(contextMapObject != null){
				String contextMapValue = contextMapObject + "";
				String cacheMapKey = exp + contextMapValue;
				String cacheMapValue = cacheMap.get(cacheMapKey);
				if(cacheMapValue != null){
					context.put(contextMapKeyOut, cacheMapValue);
				}else{
					MappedStatement mStatement = mStatementMap.get(exp);
					// System.out.println("mibatis----------------"+mStatement.getSqlSource().getBoundSql(context).getSql());
					if (mStatement != null) {
						try {
							createExecutor();
							executor.update(mStatement, context);
							List<Map<String, Object>> results = executor.query(
									mStatement, context, RowBounds.DEFAULT,
									Executor.NO_RESULT_HANDLER);
							// System.out.println("~~~~~~~~~~~~~~~~~~" +
							// results.size());
							if (results != null && !results.isEmpty()) {
								for (Map<String, Object> result : results) {
									context.putAll(result);
									cacheMap.put(cacheMapKey, result.get(contextMapKeyOut)+"");
									// System.out.println("mibatis----------------"+context);
								}
							}
							
						} catch (SQLException e) {
							e.printStackTrace();
						} finally{
							executor.close(true);
						}
					}
				}
			}
			
		}
	}

	public void init() {
		initMibatisConfig();
		initStatement();
		isInited = true;
	}

	private void initMibatisConfig() {
		config = new Configuration();
		config.setLazyLoadingEnabled(true);
		config.setUseGeneratedKeys(false);
		config.setMultipleResultSetsEnabled(true);
		config.setUseColumnLabel(true);
		config.setDefaultStatementTimeout(5000);
		config.setDefaultFetchSize(100);
	}

	private void createExecutor() {
		executor = new ReuseExecutor(config, new JdbcTransaction(dataSource,
				null, false));
	}

	private void initStatement() {
		for (String exp : extendExpressions) {
			String sql = StringUtils.trim(exp);
			sql = StringUtils.replace(sql, "$$", "#");

			System.out.println("********************************");
			System.out.println(sql);

			mStatementMap.put(exp, createStatement(sql));
		}
	}

	@SuppressWarnings("serial")
	private MappedStatement createStatement(String sql) {
		final ResultMap rm = new ResultMap.Builder(config, "defaultResultMap_"
				+ sql.hashCode(), Map.class, new ArrayList<ResultMapping>(),
				true).build();

		MappedStatement selectStatement = new MappedStatement.Builder(config,
				"selectObj_" + sql.hashCode(), new DynamicSqlSource(config,
						new TextSqlNode(sql)), SqlCommandType.SELECT)
				.resultMaps(new ArrayList<ResultMap>() {
					{
						add(rm);
					}
				}).build();

		return selectStatement;
	}

	@Override
	public void execute(List<Map<String, Object>> context) {

	}

	@Override
	public void setDay(String day) {
	}
	
	public static void main(String[] args) {
		String a = "SELECT t.create_id AS user_id FROM t_m_advertising_demand_info t WHERE t.id = $${ad_demand_id} ";
		a =StringUtils.substring(a, StringUtils.indexOf(a, "AS ")+3, StringUtils.indexOf(a, " FROM")); 
		System.out.println(a);
	}
}
